﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using Microsoft.Xna.Framework.Net;
using Momentum.Static;
using System.Text;

namespace Momentum.Types
{
    public class mTank : mObject
    {

        #region Instance Variables

        protected Texture2D m_CircleTexture;
        protected Texture2D m_TurretTexture;
        protected Texture2D m_TurretShadowTexture;
        protected float m_ObjectRotationRate;
        protected float m_TurretRotationRate;
        protected float m_TurretRotation;
        protected float m_TankFrontalAcceleration;
        protected float m_TankBackwardAcceleration;
        protected float m_MouseElasticity;

        #endregion

        #region Getters and Setters

        [ContentSerializerIgnore]
        public Texture2D CircleTexture
        {
            get { return m_CircleTexture; }
            set { m_CircleTexture = value; }
        }

        [ContentSerializerIgnore]
        public Texture2D TurretTexture
        {
            get { return m_TurretTexture; }
            set { m_TurretTexture = value; }
        }

        [ContentSerializerIgnore]
        public Texture2D TurretShadowTexture
        {
            get { return m_TurretShadowTexture; }
            set { m_TurretShadowTexture = value; }
        }

        public float ObjectRotationRate
        {
            get { return m_ObjectRotationRate; }
            set { m_ObjectRotationRate = value; }
        }

        public float TurretRotationRate
        {
            get { return m_TurretRotationRate; }
            set { m_TurretRotationRate = value; }
        }

        [ContentSerializerIgnore]
        public float TurretRotation
        {
            get { return m_TurretRotation; }
            set { m_TurretRotation = value; }
        }

        public float TankFrontalAcceleration
        {
            get { return m_TankFrontalAcceleration; }
            set { m_TankFrontalAcceleration = value; }
        }

        public float TankBackwardAcceleration
        {
            get { return m_TankBackwardAcceleration; }
            set { m_TankBackwardAcceleration = value; }
        }

        public float MouseElasticity
        {
            get { return m_MouseElasticity; }
            set { m_MouseElasticity = value; }
        }

        public bool IsAlive
        {
            get { return HP > 0; }
        }

        #endregion

        #region Initialization

        public mTank()
            : base()
        {
            this.m_Type = mStaticObject.Types.Tank;
            this.m_TurretRotation = 0.0f;
            this.m_ObjectRotationRate = 0.0f;
            this.m_TurretRotationRate = 0.0f;
            this.m_TankFrontalAcceleration = 0.0f;
            this.m_TankBackwardAcceleration = 0.0f;
            this.m_MouseElasticity = 0.0f;
            this.m_CircleTexture = null;
            this.m_ObjectTexture = null;
            this.m_ObjectShadowTexture = null;
            this.m_TurretTexture = null;
            this.m_TurretShadowTexture = null;
        }

        public void Load(ContentManager content)
        {
            this.m_CircleTexture = content.Load<Texture2D>("Tanks/Circle");
            this.m_ObjectTexture = content.Load<Texture2D>("Tanks/" + m_Name + "/Vehicle");
            this.m_ObjectShadowTexture = content.Load<Texture2D>("Tanks/" + m_Name + "/VehicleShadow");
            this.m_TurretTexture = content.Load<Texture2D>("Tanks/" + m_Name + "/Turret");
            this.m_TurretShadowTexture = content.Load<Texture2D>("Tanks/" + m_Name + "/TurretShadow");
        }

        #endregion

        #region Movement

        public void CalculateVelocity(mStaticPlayer.DirectionsFrontal fd, mStaticPlayer.DirectionsLateral ld)
        {
            float currentSpeed = 0;
            switch (fd)
            {
                case mStaticPlayer.DirectionsFrontal.Forward:
                    currentSpeed = m_TankFrontalAcceleration;
                    break;
                case mStaticPlayer.DirectionsFrontal.Backward:
                    currentSpeed = -m_TankBackwardAcceleration;
                    break;
                default:
                    break;
            }
            Velocity += new Vector2((float)(currentSpeed * Math.Cos(m_ObjectRotation)), (float)(currentSpeed * Math.Sin(m_ObjectRotation)));
            switch (ld)
            {
                case mStaticPlayer.DirectionsLateral.Right:
                    m_ObjectRotation += m_ObjectRotationRate;
                    m_TurretRotation += m_ObjectRotationRate;
                    break;
                case mStaticPlayer.DirectionsLateral.Left:
                    m_ObjectRotation -= m_ObjectRotationRate;
                    m_TurretRotation -= m_ObjectRotationRate;
                    break;
                default:
                    break;
            }
        }

        public void MoveTurret(mStaticPlayer.DirectionsTurret d)
        {
            switch (d)
            {
                case mStaticPlayer.DirectionsTurret.AntiClockWise:
                    m_TurretRotation -= m_TurretRotationRate;
                    break;
                case mStaticPlayer.DirectionsTurret.AntiClockWiseSmall:
                    m_TurretRotation -= m_TurretRotationRate / 5;
                    break;
                case mStaticPlayer.DirectionsTurret.ClockWise:
                    m_TurretRotation += m_TurretRotationRate;
                    break;
                case mStaticPlayer.DirectionsTurret.ClockWiseSmall:
                    m_TurretRotation += m_TurretRotationRate / 5;
                    break;
                default:
                    break;
            }
            if (m_TurretRotation > (float)2 * Math.PI) m_TurretRotation -= 2 * (float)Math.PI;
            else if (m_TurretRotation < 0) m_TurretRotation += 2 * (float)Math.PI;
        }

        #endregion

        #region Draw

        public override void Draw(SpriteBatch spriteBatch, Color teamColor)
        {
            base.Draw(spriteBatch, teamColor);
            // Drawing the rest
            Vector2 origenCirculo = new Vector2(this.m_CircleTexture.Width / 2, this.m_CircleTexture.Height / 2);
            Vector2 escala = new Vector2(this.m_ObjectScale, this.m_ObjectScale);
            Vector2 origenTorreta = new Vector2(this.m_TurretTexture.Width / 2, this.m_TurretTexture.Height / 2);
            Vector2 circleSize = escala * 2 * CollisionRadius / this.m_CircleTexture.Height;
            Vector2 pos = this.Position - this.m_CameraPosition + mStaticWorld.ScreenCenter;
            spriteBatch.Draw(this.m_CircleTexture, pos, null, Color.White, 0, origenCirculo, circleSize, SpriteEffects.None, 0);
            spriteBatch.Draw(this.m_TurretShadowTexture, pos + m_ShadowOffset + Vector2.One, null, teamColor, this.m_TurretRotation, origenTorreta, escala, SpriteEffects.None, 0);
            spriteBatch.Draw(this.m_TurretTexture, pos, null, teamColor, this.m_TurretRotation, origenTorreta, escala, SpriteEffects.None, 0);
            pos.Y -= 1.1f * escala.Y * this.m_ObjectTexture.Height / 2;
            String hpMessage = this.HP + "/" + this.TotalHP;
            Vector2 hpMessageSize = mStaticWorld.TankFont.MeasureString(hpMessage);
            spriteBatch.DrawString(mStaticWorld.TankFont, hpMessage, pos, new Color(0, 255, 0, 200), 0, new Vector2(hpMessageSize.X / 2, hpMessageSize.Y / 2), 1f, SpriteEffects.None, 0);
        }
        public void Draw(SpriteBatch spriteBatch, Color teamColor, string name)
        {
            Draw(spriteBatch, teamColor);
            // Drawing the name
            Vector2 escala = new Vector2(this.m_ObjectScale, this.m_ObjectScale);
            Vector2 pos = this.Position - this.m_CameraPosition + mStaticWorld.ScreenCenter;
            pos.Y += 1.1f * escala.Y * this.m_ObjectTexture.Height / 2;
            Vector2 messageSize = mStaticWorld.TankFont.MeasureString(name);
            spriteBatch.DrawString(mStaticWorld.TankFont, name, pos, new Color(0, 255, 0, 200), 0, new Vector2(messageSize.X / 2, messageSize.Y / 2), 1f, SpriteEffects.None, 0);
        }

        #endregion

        #region Serialization

        /// <summary>
        /// Serialize the object out to a packet without the heading.
        /// </summary>
        /// <param name="packetWriter">The packet to write to.</param>
        override public void SerializeWH(PacketWriter packetWriter)
        {
            base.SerializeWH(packetWriter);
            packetWriter.Write(m_TurretRotation);
        }

        public override void Deserialize(PacketReader packetReader)
        {
            base.Deserialize(packetReader);
            m_TurretRotation = packetReader.ReadSingle();
        }

        #endregion

    }

    #region Content Reader and Writer

    public class mTankContentReader : ContentTypeReader<mTank>
    {
        protected override mTank Read(ContentReader input, mTank existingInstance)
        {
            mTank tank = new mTank();
            tank.Name = input.ReadString();
            tank.CollisionRadius = input.ReadInt32();
            tank.Mass = input.ReadInt32();
            tank.ObjectScale = (float)input.ReadSingle();
            tank.ShadowOffset = input.ReadVector2();
            tank.TotalHP = input.ReadInt32();
            tank.ObjectRotationRate = (float)input.ReadSingle();
            tank.TurretRotationRate = (float)input.ReadSingle();
            tank.TankFrontalAcceleration = (float)input.ReadSingle();
            tank.TankBackwardAcceleration = (float)input.ReadSingle();
            tank.MouseElasticity = (float)input.ReadSingle();
            tank.Load(input.ContentManager);
            return tank;
        }
    }

    [ContentTypeWriter]
    public class mTankContentWriter : ContentTypeWriter<mTank>
    {
        protected override void Write(ContentWriter output, mTank tank)
        {
            output.Write(tank.Name);
            output.Write(tank.CollisionRadius);
            output.Write(tank.Mass);
            output.Write(tank.ObjectScale);
            output.Write(tank.ShadowOffset);
            output.Write(tank.TotalHP);
            output.Write(tank.ObjectRotationRate);
            output.Write(tank.TurretRotationRate);
            output.Write(tank.TankFrontalAcceleration);
            output.Write(tank.TankBackwardAcceleration);
            output.Write(tank.MouseElasticity);
        }
        public override string GetRuntimeReader(TargetPlatform targetPlatform)
        {
            return typeof(mTankContentReader).AssemblyQualifiedName;
        }
    }

    #endregion

}